package com.example.common.grpc;

import com.example.common.constants.ServiceNames;
import com.example.game.proto.internal.GrpcServiceGrpc;
import io.grpc.ManagedChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 动态gRPC客户端管理器
 * 支持根据serverId动态创建和管理不同的gRPC连接
 * 
 * @author: Allen
 * @create: 2025/1/27 11:00
 * @description: 动态gRPC客户端管理器
 **/
@Slf4j
@Component
public class DynamicGrpcClientManager {
    
    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private GrpcChannelConfig grpcChannelConfig;
    
    // 存储不同serverId的channel和stub
    private final Map<String, ManagedChannel> channels = new ConcurrentHashMap<>();
    private final Map<String, GrpcServiceGrpc.GrpcServiceBlockingStub> blockingStubs = new ConcurrentHashMap<>();
    private final Map<String, GrpcServiceGrpc.GrpcServiceStub> asyncStubs = new ConcurrentHashMap<>();
    
    /**
     * 根据serverId获取或创建BlockingStub
     */
    public GrpcServiceGrpc.GrpcServiceBlockingStub getBlockingStub(int serverId, ServiceNames serviceType) {
        String key = generateKey(serverId, serviceType);
        
        GrpcServiceGrpc.GrpcServiceBlockingStub stub = blockingStubs.get(key);
        if (stub != null) {
            return stub;
        }
        
        // 创建新的连接
        synchronized (this) {
            stub = blockingStubs.get(key);
            if (stub != null) {
                return stub;
            }
            ManagedChannel channel = channels.get(key);
            if (channel == null) {
                channel = createChannel(serverId, serviceType);
            }
            if (channel != null) {
                stub = GrpcServiceGrpc.newBlockingStub(channel);
                channels.put(key, channel);
                blockingStubs.put(key, stub);
                log.info("创建新的BlockingStub: serverId={}, serviceType={}", serverId, serviceType);
            }
        }
        
        return stub;
    }
    
    /**
     * 根据serverId获取或创建AsyncStub
     */
    public GrpcServiceGrpc.GrpcServiceStub getAsyncStub(int serverId, ServiceNames serviceType) {
        String key = generateKey(serverId, serviceType);
        
        GrpcServiceGrpc.GrpcServiceStub stub = asyncStubs.get(key);
        if (stub != null) {
            return stub;
        }
        
        // 创建新的连接
        synchronized (this) {
            stub = asyncStubs.get(key);
            if (stub != null) {
                return stub;
            }
            ManagedChannel channel = channels.get(key);
            if (channel == null) {
                channel = createChannel(serverId, serviceType);
            }
            if (channel != null) {
                stub = GrpcServiceGrpc.newStub(channel);
                channels.put(key, channel);
                asyncStubs.put(key, stub);
                log.info("创建新的AsyncStub: serverId={}, serviceType={}", serverId, serviceType);
            }
        }
        
        return stub;
    }
    
    /**
     * 根据serverId获取或创建Channel
     */
    public ManagedChannel getChannel(int serverId, ServiceNames serviceType) {
        String key = generateKey(serverId, serviceType);
        
        ManagedChannel channel = channels.get(key);
        if (channel != null) {
            return channel;
        }
        
        // 创建新的连接
        synchronized (this) {
            channel = channels.get(key);
            if (channel != null) {
                return channel;
            }
            
            channel = createChannel(serverId, serviceType);
            if (channel != null) {
                channels.put(key, channel);
                log.info("创建新的Channel: serverId={}, serviceType={}", serverId, serviceType);
            }
        }
        
        return channel;
    }
    
    /**
     * 创建gRPC Channel
     */
    private ManagedChannel createChannel(int serverId, ServiceNames serviceType) {
        try {
            // 从服务发现中获取指定serverId的实例信息
            ServiceInstance instance = findServiceInstanceByServerId(serverId, serviceType);
            if (instance == null) {
                log.warn("未找到serverId={}的{}服务实例", serverId, serviceType);
                return null;
            }
            
            // 获取gRPC端口
            int grpcPort = getGrpcPortFromInstance(instance, serviceType);
            
            // 使用GrpcChannelConfig创建优化的Channel
            ManagedChannel channel = grpcChannelConfig.createChannelByServiceType(
                    instance.getHost(), grpcPort, serviceType.value());
            
            // 检查Channel配置是否合理
            if (!grpcChannelConfig.isChannelConfigReasonable(channel)) {
                log.warn("Channel配置可能存在问题，serverId={}, serviceType={}", serverId, serviceType);
                log.info("配置建议: {}", grpcChannelConfig.getChannelConfigAdvice(serviceType.value()));
            }
            
            log.info("成功创建Channel: serverId={}, serviceType={}, host={}, grpcPort={}", 
                    serverId, serviceType, instance.getHost(), grpcPort);
            
            return channel;
            
        } catch (Exception e) {
            log.error("创建Channel失败: serverId={}, serviceType={}", serverId, serviceType, e);
            return null;
        }
    }

    public SocketAddress getGrpcSocketAddress(int serverId, ServiceNames serviceType) {
        // 从服务发现中获取指定serverId的实例信息
        ServiceInstance instance = findServiceInstanceByServerId(serverId, serviceType);
        if (instance == null) {
            log.warn("未找到serverId={}的{}服务实例", serverId, serviceType);
            return null;
        }

        // 获取gRPC端口
        int grpcPort = getGrpcPortFromInstance(instance, serviceType);

        return new InetSocketAddress(instance.getHost(), grpcPort);
    }
    
    /**
     * 根据serverId查找服务实例
     */
    private ServiceInstance findServiceInstanceByServerId(int serverId, ServiceNames serviceType) {
        try {
            List<ServiceInstance> instances = discoveryClient.getInstances(serviceType.value());
            
            for (ServiceInstance instance : instances) {
                int instanceServerId = extractServerIdFromInstance(instance);
                if (instanceServerId == serverId) {
                    return instance;
                }
            }
            
            log.warn("未找到serverId={}的{}服务实例，可用实例: {}", 
                    serverId, serviceType, instances.size());
            return null;
            
        } catch (Exception e) {
            log.error("查找服务实例失败: serverId={}, serviceType={}", serverId, serviceType, e);
            return null;
        }
    }
    
    /**
     * 从服务实例中提取服务器ID
     */
    private int extractServerIdFromInstance(ServiceInstance instance) {
        try {
            // 方法1: 从元数据中获取server.id
            String serverIdStr = instance.getMetadata().get("server.id");
            if (serverIdStr != null && !serverIdStr.isEmpty()) {
                return Integer.parseInt(serverIdStr);
            }
            
            // 方法2: 从实例ID中解析服务器ID
            String instanceId = instance.getInstanceId();
            if (instanceId != null && instanceId.contains(":")) {
                String[] parts = instanceId.split(":");
                if (parts.length >= 2) {
                    try {
                        return Integer.parseInt(parts[1]);
                    } catch (NumberFormatException e) {
                        log.debug("无法从实例ID解析服务器ID: {}", instanceId);
                    }
                }
            }
            
            log.warn("无法从服务实例中提取服务器ID: instanceId={}, metadata={}", 
                    instance.getInstanceId(), instance.getMetadata());
            return 0;
            
        } catch (Exception e) {
            log.error("提取服务器ID失败: instanceId={}", instance.getInstanceId(), e);
            return 0;
        }
    }
    
    /**
     * 从服务实例中获取gRPC端口
     */
    private int getGrpcPortFromInstance(ServiceInstance instance, ServiceNames serviceType) {
        try {
            // 方法1: 从元数据中获取grpc.server.port
            String grpcPortStr = instance.getMetadata().get("gRPC_port");
            if (grpcPortStr != null && !grpcPortStr.isEmpty()) {
                return Integer.parseInt(grpcPortStr);
            }
            
            // 方法2: 根据服务类型和Web端口计算gRPC端口
            int webPort = instance.getPort();
            return calculateGrpcPort(serviceType, webPort);
            
        } catch (Exception e) {
            log.error("获取gRPC端口失败: instanceId={}", instance.getInstanceId(), e);
            return getDefaultGrpcPort(serviceType);
        }
    }
    
    /**
     * 根据服务类型和Web端口计算gRPC端口
     */
    private int calculateGrpcPort(ServiceNames serviceType, int webPort) {
        switch (serviceType) {
            case GATE:
                return 14000 + (webPort - 4000);
            case LOBBY:
                return 15000 + (webPort - 5000);
            case GAME:
                return 16000 + (webPort - 6000);
            default:
                return getDefaultGrpcPort(serviceType);
        }
    }
    
    /**
     * 获取默认gRPC端口
     */
    private int getDefaultGrpcPort(ServiceNames serviceType) {
        switch (serviceType) {
            case GATE:
                return 14000;
            case LOBBY:
                return 15000;
            case GAME:
                return 16000;
            default:
                return 14000;
        }
    }
    
    /**
     * 生成缓存key
     */
    private String generateKey(int serverId, ServiceNames serviceType) {
        return serviceType.value() + "-" + serverId;
    }
    
    /**
     * 移除指定serverId的连接
     */
    public void removeConnection(int serverId, ServiceNames serviceType) {
        String key = generateKey(serverId, serviceType);
        
        ManagedChannel channel = channels.remove(key);
        blockingStubs.remove(key);
        asyncStubs.remove(key);
        
        if (channel != null) {
            try {
                channel.shutdown();
                log.info("关闭Channel: serverId={}, serviceType={}", serverId, serviceType);
            } catch (Exception e) {
                log.error("关闭Channel失败: serverId={}, serviceType={}", serverId, serviceType, e);
            }
        }
    }
    
    /**
     * 移除指定服务类型的所有连接
     */
    public void removeServiceConnections(ServiceNames serviceType) {
        channels.entrySet().removeIf(entry -> {
            String key = entry.getKey();
            if (key.startsWith(serviceType.value() + "-")) {
                ManagedChannel channel = entry.getValue();
                try {
                    channel.shutdown();
                    log.info("关闭Channel: {}", key);
                } catch (Exception e) {
                    log.error("关闭Channel失败: {}", key, e);
                }
                return true;
            }
            return false;
        });
        
        blockingStubs.entrySet().removeIf(entry -> 
                entry.getKey().startsWith(serviceType.value() + "-"));
        asyncStubs.entrySet().removeIf(entry -> 
                entry.getKey().startsWith(serviceType.value() + "-"));
    }
    
    /**
     * 获取连接统计信息
     */
    public void printConnectionStats() {
        log.info("=== gRPC连接统计 ===");
        log.info("Channel数量: {}", channels.size());
        log.info("BlockingStub数量: {}", blockingStubs.size());
        log.info("AsyncStub数量: {}", asyncStubs.size());
        
        for (Map.Entry<String, ManagedChannel> entry : channels.entrySet()) {
            String key = entry.getKey();
            ManagedChannel channel = entry.getValue();
            log.info("连接: {} -> 状态: {}", key, channel.getState(true));
        }
    }
    
    /**
     * 检查连接是否可用
     */
    public boolean isConnectionAvailable(int serverId, ServiceNames serviceType) {
        String key = generateKey(serverId, serviceType);
        ManagedChannel channel = channels.get(key);
        
        if (channel == null) {
            return false;
        }
        
        return channel.getState(true) == io.grpc.ConnectivityState.READY;
    }
    
    /**
     * 应用关闭时清理资源
     */
    @PreDestroy
    public void shutdown() {
        log.info("开始关闭所有gRPC连接...");
        
        for (Map.Entry<String, ManagedChannel> entry : channels.entrySet()) {
            String key = entry.getKey();
            ManagedChannel channel = entry.getValue();
            
            try {
                channel.shutdown();
                log.info("关闭Channel: {}", key);
            } catch (Exception e) {
                log.error("关闭Channel失败: {}", key, e);
            }
        }
        
        channels.clear();
        blockingStubs.clear();
        asyncStubs.clear();
        
        log.info("所有gRPC连接已关闭");
    }
} 